// ------------------------------------------------------------------------------
// 
// Copyright (c) 2007-2008 Swampware, Inc.
// 
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// 
// ------------------------------------------------------------------------------
using System;

namespace Water.Blocks
{
	/// <summary>
	/// Summary description for Block.
	/// </summary>
	public abstract class Block : Water.Operator
	{

		public Block()
		{
		}

		public abstract string Name { get; }

		public abstract bool IsRecursive { get; }

		public override object Evaluate(Water.List expressions, Water.Environment environment, Water.Evaluator evaluator)
		{
			Evaluate(expressions.NotLast(), (Water.List)expressions.Last(), environment, evaluator);

			return null;
		}

		public abstract void Evaluate(Water.List expressions, Water.List statements, Water.Environment environment, Water.Evaluator evaluator);

		public static void EvaluateBlock(Water.List statements, Water.Environment environment, bool allowBreaks, Water.Evaluator evaluator)
		{
			Water.Blocks.BlockReader reader = new Water.Blocks.BlockReader(statements);
			Water.Blocks.BlockParser parser = new Water.Blocks.BlockParser(statements, reader);


			//Push a new _Frame
			environment.Push("_Frame", new Water.Dictionary());


			try
			{
				while(reader.CanRead)
				{
					Water.Statement statement = new Water.Statement(reader.Filename, reader.LineNumber, reader.ColumnNumber, (Water.List)parser.Parse());

					environment.Push("_Statement", statement);

					object result = evaluator.Evaluate(statement.Expression, environment);
					if(result != null)
					{
						Water.Output.WriteLine(Water.Generator.QuickGenerate(result, "", ""));
					}

					environment.Pop("_Statement");

					if(allowBreaks && IsBreak(environment))
					{
						break;
					}
					if(IsReturn(environment))
					{
						break;
					}
				}
			}
			finally
			{
				//Clear _Frame
				Water.Dictionary frame = (Water.Dictionary)environment.Peek("_Frame");
				foreach(string name in frame)
				{
					environment.Pop(name);
				}
				environment.Pop("_Frame");
			}
		}

		public static bool EvaluateBoolean(object expression, Water.Environment environment, Water.Evaluator evaluator)
		{
			object value = evaluator.Evaluate(expression, environment);
			if(value == null)
			{
				throw new System.Exception("Value is null.");
			}
			else if(!(value is bool))
			{
				throw new System.Exception("Value is not a boolean.");
			}
			return (bool)value;
		}

		private static bool IsReturn(Water.Environment environment)
		{
			return (environment.Peek("_Return") != null);
		}

		private static bool IsBreak(Water.Environment environment)
		{
			return (environment.Peek("_Break") != null);
		}

		public override string ToString()
		{
			return "BLOCK " + this.Name;
		}

	}
}
